package com.zengqingfa.examples.mybatisplus.rest;

import com.zengqingfa.examples.mybatisplus.response.Result;
import com.zengqingfa.examples.mybatisplus.util.MDCUtil;
import com.zengqingfa.examples.mybatisplus.util.ThreadContext;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;

import static com.zengqingfa.examples.mybatisplus.interceptor.RequestInterceptor.TRACE_ID;

/**
 * @fileName: DemoRest
 * @author: zengqf3
 * @date: 2021-6-30 13:47
 * @description:
 */
@RestController
@Slf4j
public class DemoRest {

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @RequestMapping("/demo1")
    public Result demo1() {
        log.error("主线程traceId={}", MDC.get(TRACE_ID));
        ExecutorCompletionService ecs = new ExecutorCompletionService(threadPoolExecutor);
        ecs.submit(MDCUtil.wrap(new TestMDC(), MDC.getCopyOfContextMap()));
        return Result.success("sucess");
    }

    class TestMDC implements Callable {
        @Override
        public Object call() throws Exception {
            log.error("子线程 traceId={}", MDC.get(TRACE_ID));
            return null;
        }
    }

    @RequestMapping("/demo2")
    public Result demo2() throws Exception {
        Map<String, String> map = MDC.getCopyOfContextMap();
        log.info("主线程traceId={}", map.get(TRACE_ID));
        CompletableFuture<Result> future = CompletableFuture.supplyAsync(() -> {
            // 必须在打印日志前设置
            MDCUtil.setMDCContextMap(map);
            //todo

            log.info("主线程traceId={}", map.get(TRACE_ID));
            return Result.success("sucess");
        }, threadPoolExecutor);
        future.exceptionally(new Function<Throwable, Result>() {
            /**捕捉异常,不会导致整个流程中断**/
            @Override
            public Result apply(Throwable throwable) {
                log.error("线程[{}]发生了异常[{}], 继续执行其他线程", Thread.currentThread().getName(), throwable.getMessage());
                return Result.fail("fail");
            }
        });
        return future.get();
    }


    @RequestMapping("/demo3")
    public Result demo3() throws Exception {
        String traceId = ThreadContext.getContext().get();
        log.info("线程名称"+Thread.currentThread().getName()+"主线程traceId={}", traceId);
        CompletableFuture<Result> future = CompletableFuture.supplyAsync(() -> {
            //todo

            log.error("线程名称"+Thread.currentThread().getName()+"子线程traceId={}", ThreadContext.getContext().get());
            return Result.success("sucess");
        }, threadPoolExecutor);
        future.exceptionally(new Function<Throwable, Result>() {
            /**捕捉异常,不会导致整个流程中断**/
            @Override
            public Result apply(Throwable throwable) {
                log.info("线程[{}]发生了异常[{}], 继续执行其他线程", Thread.currentThread().getName(), throwable.getMessage());
                return Result.fail("fail");
            }
        });
        return future.get();
    }
}
